﻿using System;
using JetBrains.Annotations;

namespace Stee.CAP8.Communication.HttpClient
{
    /// <summary>
    /// Marks HttpClientProxy contract interfaces. Must be present for <see cref="HttpClientProxy"/>
    /// to be able to generate a proxy.
    /// </summary>
    [AttributeUsage(AttributeTargets.Interface)]
    public class HttpContractAttribute : Attribute
    {
        [PublicAPI] [CanBeNull] public string Namespace { get; set; }

        [PublicAPI]
        public HttpContractAttribute(string ns = null)
        {
            Namespace = ns;
        }
    }

    /// <summary>
    /// Http methods remote call.
    /// </summary>
    /// <inheritdoc />
    [AttributeUsage(AttributeTargets.Method)]
    [PublicAPI]
    public class HttpCallAttribute : Attribute
    {
        [PublicAPI]
        public HttpVerb HttpMethod { get; }

        [PublicAPI]
        [CanBeNull]
        public string Path { get; }

        [PublicAPI]
        public EncodingType BodyEncoding { get; set; }

        [PublicAPI]
        public bool LongRunning { get; set; }

        [PublicAPI]
        public HttpCallAttribute(string path = null, EncodingType bodyEncoding = EncodingType.None)
        {
            Path = path;
            HttpMethod = HttpVerb.Get;
            BodyEncoding = bodyEncoding;
        }

        [PublicAPI]
        public HttpCallAttribute(HttpVerb method, string path = null, EncodingType bodyEncoding = EncodingType.None)
        {
            HttpMethod = method;
            Path = path;
            BodyEncoding = bodyEncoding;
        }
    }

    /// <summary>
    /// GET metod call
    /// </summary>
    public class GetAttribute : HttpCallAttribute
    {
        public GetAttribute(string path = null) : base(HttpVerb.Get, path) { }
    }

    /// <summary>
    /// POST method call
    /// </summary>
    public class PostAttribute : HttpCallAttribute
    {
        public PostAttribute(string path = null) : base(HttpVerb.Post, path) { }
    }

    /// <summary>
    /// PUT method call
    /// </summary>
    public class PutAttribute : HttpCallAttribute
    {
        public PutAttribute(string path = null) : base(HttpVerb.Put, path) { }
    }

    /// <summary>
    /// DELETE method call
    /// </summary>
    public class DeleteAttribute : HttpCallAttribute
    {
        public DeleteAttribute(string path = null) : base(HttpVerb.Delete, path) { }
    }

    /// <summary>
    /// Parameters annotated with this attribute will be added as URL query parameter.
    /// </summary>
    /// <example>
    /// <code>
    /// [HttpCall("/users/get")]
    /// User GetUser([QueryParam("gid")] string GID);
    /// </code>
    /// The resulting URI will be: /users/get?gid=GID
    /// </example>
    [AttributeUsage(AttributeTargets.Parameter)]
    public class QueryParamAttribute : Attribute
    {
        [PublicAPI] public string Name { get; set; }

        [PublicAPI]
        public QueryParamAttribute(string name = null)
        {
            Name = name;
        }
    }

    /// <summary>
    /// Parameters annotated with this attribute will be inserted into the Http call
    /// URL as parameters.
    /// </summary>
    /// <example>
    /// <code>
    /// [HttpCall("/users/{GID}/get")]
    /// User GetUser([UrlParam] string GID);
    /// </code>
    /// </example>
    [AttributeUsage(AttributeTargets.Parameter)]
    public class UrlParamAttribute : Attribute
    {
        [PublicAPI] public string Name { get; set; }

        [PublicAPI]
        public UrlParamAttribute(string name = null)
        {
            Name = name;
        }
    }

    /// <summary>
    /// Marks a parameter to send as body. Multiple body parameters can
    /// be set, this case don't forget to set the proper encoding type on the method.
    /// </summary>
    [AttributeUsage(AttributeTargets.Parameter)]
    public class BodyAttribute : Attribute
    {
        [PublicAPI]
        public string Name { get; set; }

        [PublicAPI]
        public BodyAttribute(string name = null)
        {
            Name = name;
        }
    }

    /// <summary>
    /// Multipart content encoding
    /// </summary>
    public enum EncodingType
    {
        None,
        FormUrlEncoding,
        Multipart,
        MultipartForm,
    }

    /// <summary>
    /// Marks a parameter to pass as a header value.
    /// </summary>
    [AttributeUsage(AttributeTargets.Parameter)]
    public class HeaderAttribute : Attribute
    {
        [PublicAPI]
        [NotNull]
        public string Name { get; set; }

        public HeaderAttribute([NotNull] string name)
        {
            Name = name;
        }
    }

    /// <summary>
    /// Marks fixed parameter to pass as header values.
    /// </summary>
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
    [PublicAPI]
    public class AddHeaderAttribute : Attribute
    {
        [PublicAPI]
        [NotNull]
        public string Name { get; set; }
        [PublicAPI]
        [NotNull]
        public string[] Values { get; set; }

        public AddHeaderAttribute([NotNull] string name, [NotNull] params string[] values)
        {
            Name = name;
            Values = values ?? throw new ArgumentNullException(nameof(values));
        }
    }

    public enum HttpVerb
    {
        Get, 
        Post,      
        Put,
        Delete
    }
}
